
#include "micco.h"
#include "xllp_i2c.h"
#include "util.h"
#include "monahans.h"
#include "ssp.h"

#define bbu_I2C_PHYSICAL_BASE        0x40301680

#define bbu_I2C_IMBR_offset          0X00
#define bbu_I2C_IDBR_offset          0X08
#define bbu_I2C_ICR_offset           0X10
#define bbu_I2C_ISR_offset           0X18
#define bbu_I2C_ISAR_offset          0X20
#define bbu_I2C_ICCR_offset          0x28

#define bbu_ICR_IUE                  0X0040
#define bbu_ICR_SCLE                 0X0020
#define bbu_ICR_TB                   0X0008
#define bbu_ICR_ACKNAK               0x0004
#define bbu_ICR_STOP                 0x0002
#define bbu_ICR_START                0X0001

#define bbu_ISR_IRF                  0x0080
#define bbu_ISR_ITE                  0x0040
#define bbu_PI2C_EN                  0x0040
#define bbu_ISR_BED                  0x0400

#define BBU_I2C_TimeOut              0x2000

#define bbu_PMRCREGS_PHYSICAL_BASE           0x40F50000

#define bbu_PCFR_offset              0x00C
#define bbu_PI2DBR_offset            0x188
#define bbu_PI2CR_offset             0x190
#define bbu_PI2SR_offset             0x198
#define bbu_PI2SAR_offset            0x1A0
#define bbu_UASPR_offset       0x1C
#define xlli_OSCR0_offset      (0x10)

#define bbu_FFUART_PHYSICAL_BASE   0x40100000

#define xlli_OSTREGS_PHYSICAL_BASE         (0x40A00000)
#define bbu_SSP4_PHYSICAL_BASE       0x41A00000

#define xlli_CLKREGS_PHYSICAL_BASE  0x41340000
#define xlli_D0CKEN_A_offset         0x0C
#define bbu_SSP3_PHYSICAL_BASE       0x41900000

#define bbu_SSCR0_offset             0x00
#define bbu_SSCR1_offset             0x04
#define bbu_SSSRx_offset             0x08
#define bbu_SSDRx_offset             0x10
#define bbu_SSTOx_offset             0x28
#define bbu_SSPSPx_offset            0x2C
#define bbu_SSACDx_offset            0x3C
#define bbu_SSACDDx_offset           0x40

#define bbu_BIT_14                    0x00004000
#define bbu_BIT_15                    0x00008000
#define bbu_BIT_16                    0x00010000
#define bbu_BIT_17                    0x00020000
#define bbu_BIT_18                    0x00040000
#define bbu_BIT_19                    0x00080000
#define bbu_BIT_20                    0x00100000
#define bbu_BIT_21                    0x00200000
#define bbu_BIT_22                    0x00400000
#define bbu_BIT_23                    0x00800000
#define bbu_BIT_24                    0x01000000
#define bbu_BIT_25                    0x02000000
#define bbu_BIT_26                    0x04000000
#define bbu_BIT_27                    0x08000000
#define bbu_BIT_28                    0x10000000
#define bbu_BIT_29                    0x20000000
#define bbu_BIT_30                    0x40000000
#define bbu_BIT_31                    0x80000000

#define bbu_DCMD_INCSCRADDR          bbu_BIT_31
#define bbu_DCMD_INCTRGADDR          bbu_BIT_30
#define bbu_DCMD_FLOWSRC             bbu_BIT_29
#define bbu_DCMD_FLOWTRG             bbu_BIT_28
#define bbu_DCMD_SIZE_8              bbu_BIT_16
#define bbu_DCMD_SIZE_16             bbu_BIT_17
#define bbu_DCMD_SIZE_32             (bbu_BIT_17 | bbu_BIT_16)
#define bbu_DCMD_WIDTH_8             bbu_BIT_14
#define bbu_DCMD_WIDTH_16            bbu_BIT_15
#define bbu_DCMD_WIDTH_32            (bbu_BIT_15 | bbu_BIT_14)

#define bbu_DMA_DRCMR2_offset        0x010C
#define bbu_DMA_DRCMR67_offset       0x110C

#define bbu_DCSR_RUN      bbu_BIT_31
#define bbu_DMA_DDADR6_offset       (0X260)
#define bbu_DMA_DCSR6_offset        (0X018)

#define bbu_DMA_PHYSICAL_BASE       (0x40000000)

#define xlli_control_mmu   0x0001

int InitI2c(void);

void checkMemoryControlFunc()
{
	printf("testMemoryDDR control Register\n");
	printf("0x%x\n",*(unsigned long *)0x43000010);
	printf("0x%x\n",*(unsigned long *)0x4300002c);
	printf("0x%x\n",*(unsigned long *)0x43000004);

	printf("0x%x\n",*(unsigned long *)0x48100000);
	printf("0x%x\n",*(unsigned long *)0x48100004);

	printf("0x%x\n",*(unsigned long *)0x48100040);
	printf("0x%x\n",*(unsigned long *)0x48100050);
	printf("0x%x\n",*(unsigned long *)0x48100060);
	printf("0x%x\n",*(unsigned long *)0x48100068);
	printf("0x%x\n",*(unsigned long *)0x48100070);

	printf("0x%x\n",*(unsigned long *)0x48100078);
	printf("0x%x\n",*(unsigned long *)0x48100090);
	printf("0x%x\n",*(unsigned long *)0x48100114);
	printf("0x%x\n",*(unsigned long *)0x48100118);
	printf("0x%x\n",*(unsigned long *)0x4810011C);
	printf("0x%x\n",*(unsigned long *)0x48100120);
	printf("%d\n",*(unsigned long *)0x48100124);

	printf("0x%x\n",*(unsigned long *)0x48100128);
	printf("0x%x\n",*(unsigned long *)0x4810012C);
	printf("0x%x\n",*(unsigned long *)0x48100100);
	printf("0x%x\n",*(unsigned long *)0x48100000);

}

void testMemoryFunction(unsigned long src, unsigned length)
{
	unsigned long orginalVal;
	unsigned long i;
	//loop: r/w check
	for (i = 0; i < length; ++i)
	{
		orginalVal = *((unsigned long *)src + i);
		orginalVal |= 0xfff;
		*((unsigned long *)src + i) = orginalVal;

		if (orginalVal != *((unsigned long *)src + i)) {
			printf("Read,Write Memory Check Error address 0x%x\n",((unsigned long *)src + i));
		}
	}
}
/*
initStandard = 1: for standard hifi
initStandard = 0: for pcm sound
*/
void initHifiI2sBus(int initStandard)
{
	//enable ssp3 controller clock
	unsigned long CLKREGS_PHSICAL_BASE = xlli_CLKREGS_PHYSICAL_BASE;
	unsigned long DOCKEN_OFFSET = xlli_D0CKEN_A_offset;
	unsigned long val  = __REG(CLKREGS_PHSICAL_BASE+DOCKEN_OFFSET);
	val |= 0x10000000;
	__REG(CLKREGS_PHSICAL_BASE+DOCKEN_OFFSET) = val;

	//send 13MHz clock out to codec
	val = __REG(0x41350000);
	val |= 0x800;
	__REG(0x41350000) = val;

	if ( initStandard) {
		//init standard hifi
		//hifi (i2s) setup  --- configure interface for 3.702 mhz clock ,32-bit data
		val = 0x4010003F;
		__REG(bbu_SSP3_PHYSICAL_BASE+ bbu_SSCR0_offset) = val;// sscr0;

		val = 0x00A00000;
		__REG(bbu_SSP3_PHYSICAL_BASE+ bbu_SSCR1_offset) = val;// sscr1;

		val = 0x02200400;
		__REG(bbu_SSP3_PHYSICAL_BASE+ bbu_SSPSPx_offset) = val;// sspsp;

		val = 0x60;
		__REG(bbu_SSP3_PHYSICAL_BASE+ bbu_SSACDx_offset) = val; //ssacd;

		val = 0x06590040;
		__REG(bbu_SSP3_PHYSICAL_BASE+ bbu_SSACDDx_offset) = val; //ssacdd;
	}
	else
	{
		//init pcm voice
	}

	//set the port enable bit
	val = __REG(bbu_SSP3_PHYSICAL_BASE + bbu_SSCR0_offset);
	val |= 0x80;
	__REG(bbu_SSP3_PHYSICAL_BASE + bbu_SSCR0_offset) = val;

	//set up some basic codec features via the i2c bus
	//set up i2s control for 48khz audio msb justified

	micco_codec_write((0x7B - 0x70),0x9F);
	//enable dac
	micco_codec_write((0x78 - 0x70),0x80);
}

//speaker vol level 0-63
void setSpeakerVol(unsigned char vol)
{
	unsigned char val;
	val = ~vol;
	val = val & 0x3f;//mask out all unused bits
	val |= 0x40; //enable mono amp with soft start up

	//set up the bear amp (this amp must be enable to get output from the speaker)
	unsigned char r1;
	micco_codec_read(0xa, &r1);
	r1 |= 0x40;
	micco_codec_write(0xa,r1);

	//set speaker volume
	micco_codec_write(0x9,val);
	printf("speaker vol =0x%x\n", val);
}
void setHeadSetVol(unsigned char vol)
{
	unsigned char val;
	val = ~vol;
	val = val & 0x3f;//mask out all unused bits
	val |= 0x40; //enable mono amp with soft start up

	//set up the bear volume
	micco_codec_write(0xa, val);

	//The MONO amp must also be enabled to get audio out of the BEAR amplifier
	u8  r1;
	micco_codec_read(0x9, &r1);
	r1 |= 0x40;
	micco_codec_write(0x9, r1);
}

//static struct ssp_dev ssp3;

XLLP_STATUS_T XllpI2cInit(P_XLLP_I2C_T I2C_regs,
						  P_XLLP_VUINT32_T pMfpRegBase,
						  P_XLLP_MFP_RM_DB_ID_T  pMfpRmDb,
						  XLLP_UINT32_T dev_id);

unsigned int testSameple[] = {
	0x00000000,   0x0,  0x10B50000,   0x0,   0x21200000, 0x0,     0x30FB0000,0x0,
	0x3FFF0000,  0x0,    0x4DEB0000,  0x0,    0x5A820000, 0x0,     0x658C0000,0x0,
	0x6ED90000,   0x0,   0x76410000,  0x0,    0x7BA30000,  0x0,    0x7EE70000,0x0,
	0x7FFF0000,  0x0,    0x7EE70000,  0x0,    0x7BA30000,   0x0,   0x76410000,0x0,
	0x6ED90000,   0x0,   0x658C0000,  0x0,    0x5A820000,  0x0,    0x4DEB0000,0x0,
	0x3FFF0000,   0x0,   0x30FB0000,  0x0,    0x21200000,   0x0,   0x10B50000,0x0,
	0x00000000, 0x0,     0xEF4B0000,  0x0,    0xDEE00000,  0x0,    0xCF050000,0x0,
	0xC0000000,   0x0,   0xB2150000,  0x0,    0xA57E0000,   0x0,   0x9A740000,0x0,
	0x91270000,  0x0,    0x89BF0000,  0x0,    0x845D0000,   0x0,   0x81190000,0x0,
	0x80000000,  0x0,    0x81190000,  0x0,    0x845D0000,   0x0,   0x89BF0000,0x0,
	0x91270000,  0x0,    0x9A740000,   0x0,   0xA57E0000,   0x0,   0xB2150000,0x0,
	0xC0000000, 0x0,     0xCF050000,   0x0,   0xDEE00000,    0x0,  0xEF4B0000,0x0,
};

typedef struct
{
	XLLP_VUINT32_T   ddadr;  ///< descriptor address reg
	XLLP_VUINT32_T   dsadr;  ///< source address register
	XLLP_VUINT32_T   dtadr;  ///< target address register
	XLLP_VUINT32_T   dcmd;   ///< command address register
}XLLP_DMAC_DESCRIPTOR_T;

void dmaAudioTest(int turnOffOrOn)
{
	__REG(bbu_DMA_PHYSICAL_BASE + bbu_DMA_DCSR6_offset ) = 0x0;
	if (turnOffOrOn ==0) return; //turnoff

	//create sound file
	unsigned int ii = 0;
	while (ii < sizeof(testSameple)/sizeof(int)) {
		*((unsigned short int*)(0x80200000)+ ii)  = testSameple[ii];
		ii++;
	}
	XLLP_DMAC_DESCRIPTOR_T *p = (XLLP_DMAC_DESCRIPTOR_T*)(0x80100000);

	__REG(bbu_DMA_PHYSICAL_BASE+ bbu_DMA_DDADR6_offset) = (0x80100000); //descriptor
	p->ddadr = 0x80100000;

	p->dsadr = (XLLP_VUINT32_T)(0x80200000);
	p->dtadr = (XLLP_VUINT32_T)(bbu_SSP3_PHYSICAL_BASE + bbu_SSDRx_offset);
	p->dcmd = (bbu_DCMD_INCSCRADDR | bbu_DCMD_FLOWTRG | bbu_DCMD_SIZE_32 | 0xC180);

	__REG(bbu_DMA_PHYSICAL_BASE + bbu_DMA_DRCMR2_offset) = 0;
	__REG(bbu_DMA_PHYSICAL_BASE + bbu_DMA_DRCMR67_offset) = 0x86;

	__REG(bbu_DMA_PHYSICAL_BASE + bbu_DMA_DCSR6_offset) = bbu_DCSR_RUN;

	micco_codec_write((0x84 - 0x70),  0x05);
	micco_codec_write((0x70 - 0x70),  0x18);
	micco_codec_write((0x71 - 0x70),  0x18);
}

void testtest()
{
	printf("bootloader128 audio test\n");

	printf("a = %x, b= %x, c =%x ,d =%x\n",*((int*)0x80100000),*((int*)0x80100004),*((int*)0x80100008),*((int*)0x8010000c));
	printf("SSSR_P 0x%x\n",SSSR_P(3));

	printf("reg dma run 0x%x\n",__REG(0x40000018));

	printf("SSCR0_P 0x%x\n",SSCR0_P(3));
	printf("SSCR1_P 0x%x\n",SSCR1_P(3));
	printf("SSPSP_P 0x%x\n",SSPSP_P(3));
	printf("SSACD_P 0x%x\n",SSACD_P(3));
	printf("SSACDD_P 0x%x\n",SSACDD_P(3));

	unsigned char r1;
	micco_codec_read(0x9, &r1);
	printf("spek vol =0x%x\n", r1);

}

void asmTest(int turnOffOrOn)
{
	if (turnOffOrOn !=0 ) {
		initHifiI2sBus(1);
	}
	setSpeakerVol(turnOffOrOn);//if turnOffOrOn >0 , standard the volume
	// 	setHeadSetVol(45);

	dmaAudioTest(turnOffOrOn);
}
void pxa3xx_enable_ssp3_pins(void);
void initCodec(void)
{
	pxa3xx_enable_ssp3_pins();
	checkMemoryControlFunc();

	//i2c
	InitI2c();
	asmTest(60);
	//    testtest();

	printf("Do you hear a 1KHz tone from the speaker? \n");

#define DELAY_AUDIO 1000000   //1000000
	ostdelay(DELAY_AUDIO);
	asmTest(0);

	return;
}

//============================
//  Used For Test
int AudioInit(void)
{
    printf("\nAudioInit()--zzb");
    initCodec();

    return 0;
}

int Codec_SetVolume(unsigned char left, unsigned char right, unsigned int volType)
{
    unsigned char vol;
    vol = (left > right) ? left : right;
    setSpeakerVol(vol);
    return 0;
}

int PlaySound()
{
    dmaAudioTest(1);
    return 0;
}

void Audio_Close(void)
{
    ostdelay(1000000);
    asmTest(0);
}
